package com.example.lucene;

import com.example.lucene.model.KnowledgeBase;
import com.example.lucene.model.KnowledgebaseProblemClassification;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

import java.io.File;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @Author yanggld
 * @Date 2019/5/24-16:37
 * @Description
 */
public class IndexManager {

	private static ConcurrentMap<String, String> _createdIndexDic = new ConcurrentHashMap<>();
	/**
	 * 创建当前文件目录的索引
	 *
	 * @param indexDir       索引目录
	 * @param knowledgeBases 创建索引的知识库列表
	 * @return 是否成功
	 */
	public static boolean createIndex(String indexDir, List<KnowledgeBase> knowledgeBases, String mode) {
		//List<KnowledgeBase> knowledgeBases = GetKnowledgeBaseList(path);
		if (knowledgeBases == null || knowledgeBases.size() <= 0) {
			System.out.println("CreateIndex stop because KnowledgeBase count is null or zero.");
			return true;
		}

		//尽量避免同一个产品进行同时的索引建置
		String createdIndexItem = _createdIndexDic.get(indexDir);
		if (createdIndexItem == null) {
			_createdIndexDic.putIfAbsent(indexDir, indexDir);
		} else {
			System.out.println("CreateIndex stop because path: " + indexDir + " is creating index.");
			return false;
		}
		//先在暂存目录上生成索引
		File fileIndex;
		String tempIndexDir;
		if(mode.equals("appendOrDelete")){
			//如果是追加模式，就直接针对现有目录做处理
			fileIndex = new File((tempIndexDir = indexDir));
		}else{
			fileIndex = new File((tempIndexDir = indexDir + "_$IDXTEM$"));
			//先删除旧的暂存索引目录
			deleteDir(fileIndex);
			//再创建暂存索引目录
			fileIndex.mkdir();
		}

		IndexWriter writer = null;
		try {
			Analyzer analyzer = new StandardAnalyzer();//);//AnsjAnalyzer(TYPE.index_ansj); // StandardAnalyzer(); //(Version.LUCENE_CURRENT); //MMSegAnalyzer(); // WhitespaceAnalyzer(Version.LUCENE_CURRENT); //new StandardAnalyzer(Version.LUCENE_CURRENT);
			Directory directory = FSDirectory.open(Paths.get(tempIndexDir)); //(new File(INDEX_DIR));

			IndexWriterConfig config = new IndexWriterConfig(analyzer);//(Version.LUCENE_CURRENT, analyzer);
//			config.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
			writer = new IndexWriter(directory, config);
			for (KnowledgeBase knowledgeBase : knowledgeBases) {
//				//移除失效的知識點
//				if(knowledgeBase.getValidCode().equals("2")){
//					try {
//						//透过知识库唯一主键来删除已建立的文件索引
//						writer.deleteDocuments(new Term("knowledgeBaseId", Long.toString(knowledgeBase.getKnowledgeBaseId())));
//						writer.commit();
//					} catch (Exception e) {
//						e.printStackTrace();
//					}
//					continue;
//				}
				String searchContent = knowledgeBase.getTitle() + " " + knowledgeBase.getContent() + " " + knowledgeBase.getKeyWords();
				try {
					Document document = new Document();
					//TextField=分词、索引
					//searchContent为主要搜索对象，须要分词且建立索引
					document.add(new TextField("searchContent", searchContent, Field.Store.YES));
					//StoredField=不分词、不索引
					//title、content、keyWords等因为已经合并成searchContent字段，因此其余的就不分词也不索引
					document.add(new StoredField("title", knowledgeBase.getTitle()));
					document.add(new StoredField("content", knowledgeBase.getContent()));
					document.add(new StoredField("keyWords", knowledgeBase.getKeyWords()));
					//StringField=不分词、索引
					//id及category，applicableVersion通常做为搜寻因此要建索引，但没有分词的必要
					document.add(new StringField("knowledgeBaseId", Long.toString(knowledgeBase.getKnowledgeBaseId()), Field.Store.YES));
					document.add(new StringField("knowledgeBaseCategory", knowledgeBase.getKnowledgeBaseCategory(), Field.Store.YES));
					document.add(new StringField("applicableVersion", knowledgeBase.getApplicableVersion(), Field.Store.YES));
					//md5Str、isWechatSearched、fileName、previewImageFileName等没有搜索及分词的必要
					document.add(new StoredField("md5Str", knowledgeBase.getMd5Str()));
					document.add(new StoredField("isWechatSearched", knowledgeBase.getIsWechatSearched()));
					document.add(new StoredField("fileName", knowledgeBase.getFileName()));
					document.add(new StoredField("previewImageFileName", knowledgeBase.getPreviewImageFileName()));
					document.add(new StoredField("applicableVersion", knowledgeBase.getApplicableVersion()));
					List<KnowledgebaseProblemClassification> problemClassifications = knowledgeBase.getProblemClassifications();
					//处理知识点类别
					if (problemClassifications != null && problemClassifications.size() > 0) {
						for (KnowledgebaseProblemClassification classification : problemClassifications) {
							//classificationId目前没有做分词及索引的必要
							//id不可能為空，必定有值，不判空
							document.add(new StoredField("classificationId", classification.getProblemClassificationId()));
							String name = classification.getProblemClassificationName();
							if (name != null && !(name = name.trim()).isEmpty()) {
								//classificationName可能会被搜寻，因此有索引必要，但不需要分词
								document.add(new StringField("classificationName", name, Field.Store.YES));
							} else{
								//为了确保数组顺序一致，因此塞入一个空字串
								document.add(new StoredField("classificationName", ""));
							}
							String description = classification.getDescription();
							if (description != null && !(description = description.trim()).isEmpty()) {
								//classificationDescription目前没有做分词及索引的必要
								document.add(new StoredField("classificationDescription", description));
							} else{
								//为了确保数组顺序一致，因此塞入一个空字串
								document.add(new StoredField("classificationDescription", ""));
							}
						}
					}
					writer.addDocument(document);
					writer.commit();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			if (writer != null) {
				try {
					writer.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			//新建模式
			if(mode.equals("create")) {
				File oldIndexFolder = new File(indexDir);
				//删除旧的索引目录
				deleteDir(oldIndexFolder);
				//重新命名暂存索引目录为索引目录名称
				fileIndex.renameTo(oldIndexFolder);
			}
			//最终从字典内移除
			_createdIndexDic.remove(indexDir);
		}
//        Date date2 = new Date();
//        System.out.println("创建索引-----耗时：" + (date2.getTime() - date1.getTime()) + "ms\n");
		return true;
	}


	/**
	 * 删除文件目录下的所有文件
	 *
	 * @param file 要删除的文件目录
	 * @return 如果成功，返回true.
	 */
	public static boolean deleteDir(File file) {
		boolean isSuccess = true;
		//是目录先删除目录内的文件
		if (file.isDirectory()) {
			File[] files = file.listFiles();
			for (int i = 0; i < files.length; i++) {
				isSuccess &= deleteDir(files[i]);
			}
		}
		//最终删除目录本身(或档案本身)
		boolean deleteResult = file.delete();
		//如果删除失败，将路径输出出来
		if (!deleteResult) {
			System.out.print("delete file : " + file.getAbsoluteFile() + " failed.");
		}
		isSuccess &= deleteResult;
		return isSuccess;
	}


	public static KnowledgeBaseGetResponse searchIndex(String text, boolean isPrecision, String applicableVersion, String indexDir, String knowledgeBaseCategory, String classification) {
		KnowledgeBaseGetResponse knowledgeBaseGetResponse = new KnowledgeBaseGetResponse();
		knowledgeBaseGetResponse.setAllCount(0);
		knowledgeBaseGetResponse.setQaCount(0);
		knowledgeBaseGetResponse.setTwCount(0);
		knowledgeBaseGetResponse.setVideoCount(0);
		List<KnowledgeBaseInfo> knowledgeBaseInfos = new ArrayList<>();
		Directory directory = null;
		DirectoryReader ireader = null;
		int upCount = 0;
		boolean isImportant;
		try {
			directory = FSDirectory.open(Paths.get(indexDir));
			ireader = DirectoryReader.open(directory);
			IndexSearcher isearcher = new IndexSearcher(ireader);
			//取得命中文字的集合
			HitsResult hitsResult = getHitsDoc(text, knowledgeBaseCategory, classification, isPrecision,applicableVersion, isearcher);
			ScoreDoc[] hits = hitsResult.getScoreDoc();
			Integer size = hitsResult.getSplitWordsSize();
			for (int i = 0; i < hits.length; i++) {
				Document hitDoc = isearcher.doc(hits[i].doc);
				isImportant = false;
				String searchContent = hitDoc.get("searchContent");
				//searchContent不可能為空，為空不會命中
				//分詞超過1組時才處理
				if (size > 1) {
					//關鍵字搜索
					if (isPrecision) {
						//不完全命中搜索詞就跳過
						if (!searchContent.contains(text)) {
							continue;
						}
						//模糊搜索
					} else {
						//完全命中就往上提
						if (searchContent.contains(text)) {
							isImportant = true;
						}
					}
				}
				KnowledgeBaseInfo knowledgeBaseInfo = new KnowledgeBaseInfo();
				knowledgeBaseInfo.setKnowledgeBaseId(Long.parseLong(hitDoc.get("knowledgeBaseId")));
				knowledgeBaseInfo.setTitle(hitDoc.get("title"));
				knowledgeBaseInfo.setContent(hitDoc.get("content"));
				knowledgeBaseInfo.setKnowledgeBaseCategory(hitDoc.get("knowledgeBaseCategory"));
				knowledgeBaseInfo.setMd5Str(hitDoc.get("md5Str"));
				knowledgeBaseInfo.setIsWechatSearched(hitDoc.get("isWechatSearched"));
				knowledgeBaseInfo.setFileName(hitDoc.get("fileName"));
				knowledgeBaseInfo.setPreviewImageFileName(hitDoc.get("previewImageFileName"));
				knowledgeBaseInfo.setApplicableVersion(hitDoc.get("applicableVersion"));
				knowledgeBaseInfo.setProblemClassifications(GetClassification(hitDoc));
				//重要的往上提
				if (isImportant) {
					knowledgeBaseInfos.add(upCount, knowledgeBaseInfo);
					upCount++;
				} else {
					knowledgeBaseInfos.add(knowledgeBaseInfo);
				}
				if (("").equals(knowledgeBaseCategory)){
					knowledgeBaseGetResponse.setAllCount(knowledgeBaseGetResponse.getAllCount() + 1);
				}
				knowledgeBaseGetResponse.setQaCount(knowledgeBaseGetResponse.getQaCount() + (hitDoc.get("knowledgeBaseCategory").equals("0") ? 1 : 0));
				knowledgeBaseGetResponse.setTwCount(knowledgeBaseGetResponse.getTwCount() + (hitDoc.get("knowledgeBaseCategory").equals("1") ? 1 : 0));
				knowledgeBaseGetResponse.setVideoCount(knowledgeBaseGetResponse.getVideoCount() + (hitDoc.get("knowledgeBaseCategory").equals("3") ? 1 : 0));
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DisposeReaderOrDirectory(ireader, directory);
		}
		knowledgeBaseGetResponse.setKnowledgeBaseInfos(knowledgeBaseInfos);
		return knowledgeBaseGetResponse;
	}
}
